package nautilus.tank.model;

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.geom.AffineTransform;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import javax.imageio.ImageIO;

import nautilus.tank.Constant;
import nautilus.tank.coord.Matrix3D;

public class Tank extends MovingObject implements IVehicleWeapon{
	private List<Gun> guns = new ArrayList<Gun>();
	private Gun mainGun;
	
	private boolean isTurning = false;
	private float gunDirection = 0;
	
	public Tank(){
		try {
			x = y = 400;
			sprites = new Image[1];
			//sprites[0] = ImageIO.read(new File("D:\\Projects\\my-tank-game\\artwork\\tank4.png"));
			sprites[0] = ImageIO.read(new File(Constant.EXECUTING_FOLDER, "tank4.png"));
			spriteIndex = 0;
			width = sprites[0].getWidth(null);
			height = sprites[0].getHeight(null);
			velocityX = direction[0];
			velocityY = direction[1];
			velocityZ = direction[2];
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	public Tank(String imagePath){
		try {
			x = y = 100;
			sprites = new Image[1];
			sprites[0] = ImageIO.read(new File(Constant.EXECUTING_FOLDER, imagePath));
			spriteIndex = 0;
			width = sprites[0].getWidth(null);
			height = sprites[0].getHeight(null);
			velocityX = direction[0];
			velocityY = direction[1];
			velocityZ = direction[2];
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void fire(int amord, float x, float y) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void reload() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void moveTo(float x, float y) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void turn(float alpha) {
		// TODO Auto-generated method stub
		
	}
	
	/**
		2D only
		determine which side of line ab that point c is lying on 
	*/
	public boolean isLeft(float[] a, float[] b, float[] c){
	     return ((b[0] - a[0])*(c[1] - a[1]) - (b[1] - a[1])*(c[0] - a[0])) > 0;
	}
	
	/**
		2D only
		determine which side of line ab that point c is lying on 
	*/
	public boolean isLeft(float ax, float ay, float bx, float by,
			float cx, float cy){
	     return ((bx - ax)*(cy - ay) - (by - ay)*(cx - ax)) > 0;
	}
	
	/**
		2D only
		cs = cos(theta);
		sn = sin(theta);
		rx = x * cos - y * sin;
		ry = x * sin + y * cos;
		
		@param theta in radian
	*/
	private void rotate(float[] rs, float[] v, float theta){
		float cs = (float)Math.cos(theta);
		float sn = (float)Math.cos(theta);
		
		rs[0] = v[0] * cs - v[1]*sn;
		rs[1] = v[0] * sn + v[1]*cs;
	}
	
	public float[] getP2(){
		float x2 = x - velocityX;
		float y2 = y - velocityY;
		//float z2 = z - velocityZ;
		return new float[]{x2, y2 /*, z2 */};
	}
	
	/** used for moveStep */
	private float[] u = new float[3];
	float[] p2 = {0f, 0f};
	@Override
	protected void moveStep() {
		//TODO1: check if this object hit other moving object
		//TODO2: check if this object hit some static object
		//TODO3: check if this object hit border of the map
		
		if(currentAction == null || currentAction.isDone()){
			if(actions.isEmpty()) {
				moving = false;
				return;
			}
			currentAction = actions.remove();
		}
			
		u[0] = currentAction.getX() - x;
		u[1] = currentAction.getY() - y;
		u[2] = currentAction.getZ() - z;
		
		int kind = currentAction.getKind();
		/**
			u . v = |u|.|v|.cos(theta)
			(u dot v) / (length(u) * length(v)) > 1 - epsilon
		*/
		double lenUV = Math.sqrt(u[0]*u[0] + u[1]*u[1] + u[2]*u[2]) * Math.sqrt(velocityX*velocityX + velocityY*velocityY
					+ velocityZ*velocityZ);
		double dot = (u[0] * velocityX + u[1] * velocityY + u[2] * velocityZ) / lenUV;
		
		if( (kind & ActionOrder.MOVE_FORWARD) == ActionOrder.MOVE_FORWARD ){
			if( Math.abs(1 - dot) > Constant.OneDegree ){
				p2[0] = x - velocityX;
				p2[1] = y - velocityY;
				//turn right or left by normal vector of the plane that the tank is 
				//lying on
				if(isLeft(x, y, p2[0], p2[1], currentAction.getX(), currentAction.getY()))
					Matrix3D.rotateM(direction, x,  y,  z, Constant.OneDegree, 
							plane.normal[0], plane.normal[1], plane.normal[2]);
				else
					Matrix3D.rotateM(direction, x,  y,  z, -Constant.OneDegree, 
							plane.normal[0], plane.normal[1], plane.normal[2]);
				velocityY = direction[0];
				velocityX = direction[1];
				velocityZ = direction[2];
			} else{
				actions.add(currentAction);
				currentAction = new ActionOrder();
				currentAction.setKind(ActionOrder.MOVE_BACKWARD);
				//rotate 120 degree
			}

			lenUV = Math.sqrt(u[0]*u[0] + u[1]*u[1] + u[2]*u[2]);
			if(lenUV > 10){
				x += velocityX;
				y += velocityY;
				z += velocityZ;
				return;
			}
		} else if( (kind & ActionOrder.MOVE_BACKWARD) == ActionOrder.MOVE_BACKWARD ) {
			x += -velocityX;
			y += -velocityY;
			z += -velocityZ;
		}
			
		//float dx = (currentAction.getX() - x);
		//float dy = (currentAction.getY() - y);
		//float dz = (currentAction.getZ() - z);
		//lenUV = Math.sqrt(dx*dx + dy*dy + dz*dz);
		
		if( (kind & ActionOrder.FIRE) == ActionOrder.FIRE ){
		} 
	}
	
	/*
	public void draw(Graphics2D g2, AffineTransform transform){
		AffineTransform oldTransform = g2.getTransform();
		g2.rotate(direction, x, y);
		g2.drawImage(sprites[spriteIndex], (int)x - sprites[spriteIndex].getWidth(null)/2, (int)y - sprites[spriteIndex].getHeight(null)/2, null);
		
		if(selected){
			g2.drawRect((int)x - sprites[spriteIndex].getWidth(null)/2 -2, (int)y - sprites[spriteIndex].getHeight(null)/2 -2, 
					sprites[spriteIndex].getWidth(null)+4, sprites[spriteIndex].getHeight(null) + 4);
		}
		g2.setTransform(oldTransform);
		spriteIndex++;
		if(spriteIndex >= sprites.length)
			spriteIndex = 0;
	}
	*/
	
	public void draw(Graphics2D g2, AffineTransform transform){
		
	}
}
